package io.task.cc.message.socket.task;

import io.task.cc.message.socket.ChannelContext;
import io.task.cc.message.socket.maintain.MaintainUtils;
import io.task.cc.message.socket.spi.client.ClientChannelContext;
import io.task.cc.message.socket.spi.client.ClientConfig;
import io.task.cc.message.socket.spi.client.ReconnConf;
import io.task.cc.message.socket.thread.pool.QueueModeSynchronousTask;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import java.util.Queue;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * @author huihui
 */
@Slf4j
@Setter
@Getter
public class CloseTask extends QueueModeSynchronousTask<ChannelContext> {


    public CloseTask(Executor executor) {
        super(executor);
        getMsgQueue();
    }


    @Override
    public void runTask() {
        if (msgQueue.isEmpty()) {
            return;
        }
        ChannelContext channelContext = null;
        while ((channelContext = msgQueue.poll()) != null) {
            //			System.out.println(count++);
            try {
                boolean isNeedRemove = channelContext.closeMeta.isNeedRemove;
                String remark = channelContext.closeMeta.remark;
                Throwable throwable = channelContext.closeMeta.throwable;


                channelContext.stat.timeClosed = System.currentTimeMillis();


                try {
                    //					channelContext.traceClient(ChannelAction.UNCONNECT, null, null);

                    if (channelContext.isClosed && !isNeedRemove) {
                        log.info("{}, {}已经关闭，备注:{}，异常:{}", channelContext.config, channelContext, remark, throwable == null ? "无" : throwable.toString());
                        return;
                    }

                    if (channelContext.isRemoved) {
                        log.info("{}, {}已经删除，备注:{}，异常:{}", channelContext.config, channelContext, remark, throwable == null ? "无" : throwable.toString());
                        return;
                    }

                    //必须先取消任务再清空队列
                    channelContext.decodeRunnable.setCanceled(true);
                    channelContext.handlerRunnable.setCanceled(true);
                    channelContext.sendRunnable.setCanceled(true);

                    channelContext.decodeRunnable.clearMsgQueue();
                    channelContext.handlerRunnable.clearMsgQueue();
                    channelContext.sendRunnable.clearMsgQueue();

                    log.info("{}, {} 准备关闭连接, isNeedRemove:{}, {}", channelContext.config, channelContext, isNeedRemove, remark);

                    try {
                        if (isNeedRemove) {
                            MaintainUtils.remove(channelContext);
                        } else {
                            ClientConfig tioClientConfig = (ClientConfig) channelContext.config;
                            tioClientConfig.closeds.add(channelContext);
                            tioClientConfig.connecteds.remove(channelContext);
                            MaintainUtils.close(channelContext);
                        }

                        channelContext.setRemoved(isNeedRemove);

                        channelContext.stat.timeClosed = System.currentTimeMillis();
                        channelContext.setClosed(true);
                    } catch (Throwable e) {
                        log.error(e.toString(), e);
                    } finally {
                        if (!isNeedRemove && channelContext.isClosed && !channelContext.isServer()) //不删除且没有连接上，则加到重连队列中
                        {
                            ClientChannelContext clientChannelContext = (ClientChannelContext) channelContext;
                            ReconnConf.put(clientChannelContext);
                        }
                    }
                } catch (Throwable e) {
                    log.error(throwable.toString(), e);
                }

            } finally {
                channelContext.isWaitingClose = false;
            }
        }
    }


    private final Queue<ChannelContext> msgQueue = new LinkedBlockingQueue<>();

    @Override
    public Queue<ChannelContext> getMsgQueue() {

        return msgQueue;
    }
}
